package com.boarsoft.message.store.jdbc;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.boarsoft.common.Util;
import com.boarsoft.common.util.JsonUtil;
import com.boarsoft.message.MessageConfig;
import com.boarsoft.message.bean.Message;
import com.boarsoft.message.bean.MessageEntity;
import com.boarsoft.message.bean.MessageQueryParam;
import com.boarsoft.message.store.MessageRoller;
import com.boarsoft.serialize.ObjectSerializer;

public abstract class MsgMainTM extends MsgBaseTM {
	private static final Logger log = LoggerFactory.getLogger(MsgMainTM.class);

	/** 表示数据表是针对文件存储的索引 */
	public static final short TYPE_FILE = 0;
	/** 表示数据表以JSON格式保存消息 */
	public static final short TYPE_JSON = 1;
	/** 表示数据表以BLOB格式保存序列化后的消息 */
	public static final short TYPE_BLOB = 2;

	/** 用于恢复未发送成功的主消息 */
	protected String reloadSql;

	/** 对象序列化器，type=TYPE_BLOB 时有效 */
	protected ObjectSerializer serializer;
	/** 查询时的分页大小（用于从数据表中恢复数据，一次从表中查询的消息数） */
	protected int pageSize = 200;
	/** 消息存储（在字段中的）的格式 */
	protected short type = TYPE_JSON;

	protected MsgDetailTM detailTm;

	public MsgMainTM(String target) {
		super(target.concat("_m"));
		this.prepareReloadSql();
	}

	protected String getLob() {
		switch (type) {
		case TYPE_JSON:
			return "vJson";
		case TYPE_BLOB:
			return "bBlob";
		}
		return null;
	}

	@Override
	protected void prepareGet() {
		StringBuilder sb = new StringBuilder();
		sb.append("select iAddTime, tStatus, tTried, ").append(this.getLob());
		sb.append(" from ").append(table).append(" where cId = ?");
		this.getSql = sb.toString();
	}

	@Override
	protected void prepareUpdate() {
		StringBuilder sb = new StringBuilder("update ").append(table);
		sb.append(" set tStatus = ?, vMemo = ?, iLastTime = ?, tTried = ? where cId = ?");
		this.updateSql = sb.toString();
	}

	@Override
	protected void prepareInsert() {
		StringBuilder sb = new StringBuilder();
		sb.append("insert into ").append(table).append(" (cId, iAddTime, vNode,")//
				.append(this.getLob()).append(") values (?, ?, ?, ?)");
		this.insertSql = sb.toString();
	}

	public void insert(Connection conn, Message m) throws SQLException, IOException {
		PreparedStatement ps = null;
		try {
			ps = conn.prepareStatement(insertSql);
			ps.setString(1, m.getId());
			ps.setLong(2, new Date().getTime());
			ps.setString(3, MessageConfig.getAddr());
			switch (type) {
			case TYPE_JSON:
				// ps.setString(3, JsonUtil.from(m));
				// ps.setString(3, JsonUtil.toJson(m));
				ps.setString(4, JsonUtil.toJSONString(m));
				break;
			case TYPE_BLOB:
				ps.setBytes(4, serializer.serialize(m));
				break;
			}
			ps.executeUpdate();
		} finally {
			JdbcUtil.close(ps);
		}
	}

	// 查询失效消息数量的sql
	private String prepareExpiredNum(short... statuses) {
		StringBuilder sb = new StringBuilder();
		sb.append("select count(1) as num from ");
		sb.append(table).append(" where iAddTime<= ? and tStatus in ( ");
		for (int i = 0; i < statuses.length; i++) {
			if (i != (statuses.length - 1)) {
				sb.append("?,");
			} else {
				sb.append("?)");
			}
		}
		return sb.toString();
	}

	// 统计备份表数据数量的sql
	private String prepareBackupNum(String tabName) {
		StringBuilder sb = new StringBuilder();
		sb.append("select count(1) as num from ").append(tabName);
		String sql = sb.toString();
		log.info("统计备份表数据数量的sql：{}", sql);
		return sql;
	}

	// 迁移过期数据到备份表的sql
	private String prepareMoveData(String backupTable, int pageSize, short... statuses) {
		StringBuilder sb = new StringBuilder();
		sb.append("INSERT INTO ").append(backupTable).append(" SELECT * FROM ").append(table)
				.append(" where iAddTime<= ? and tStatus in ( ");
		for (int i = 0; i < statuses.length; i++) {
			if (i != (statuses.length - 1)) {
				sb.append("?,");
			} else {
				sb.append("?)");
			}
		}
		sb.append(" limit ").append("0,").append(pageSize);
		String sql = sb.toString();
		log.info("迁移过期数据到备份表的sql：{}", sql);
		return sql;
	}

	// 批次删除过期数据的sql
	private String prepareDelExpiredData(String tableName) {
		StringBuilder sb = new StringBuilder("delete m.* from ").append(tableName).append(" b,").append(table).append(" m")
				.append(" where m.cId = b.cId ");
		String sql = sb.toString();
		log.info("删除main表过期数据sql:{}", sql);
		return sql;
	}

	// 删除过期数据的sql
	private String prepareDelExpiredData(short... statuses) {
		StringBuilder sb = new StringBuilder();
		sb.append("DELETE FROM ").append(table).append(" WHERE iAddTime<=? and tStatus in ( ");
		for (int i = 0; i < statuses.length; i++) {
			if (i != (statuses.length - 1)) {
				sb.append("?,");
			} else {
				sb.append("?)");
			}
		}
		String sql = sb.toString();
		log.info("删除main表过期数据sql:{}", sql);
		return sql;
	}

	// 删除已备份的数据sql
	protected String prepareDelete(String tableName) {
		StringBuilder sb = new StringBuilder("delete b.* from ").append(tableName).append(" b,").append(table).append(" m")
				.append(" where m.cId = b.cId ");
		String sql = sb.toString();
		log.info("删除已备份数据sql:{}", sql);
		return sql;
	}

	/**
	 * 为前端管理页面提供的分页查询语句
	 * 
	 * @param param
	 * @return
	 */
	protected String prepareList(MessageQueryParam param) {
		StringBuilder sb = new StringBuilder();
		sb.append("select cId, iAddTime, iLastTime, tStatus, tTried, vMemo");
		if (param.isLob()) {
			sb.append(", ").append(this.getLob());
		}
		sb.append(" from ").append(table);
		sb.append(" where 1=1 ");
		prepareCondition(sb, param);
		sb.append(" order by iAddTime desc limit ?,? ");
		log.info("main分页查询sql:{}", sb.toString());
		return sb.toString();
	}

	// 组装分页查询条件sql
	protected void prepareCondition(StringBuilder sb, MessageQueryParam param) {
		if (Util.strIsNotEmpty(param.getId())) {
			sb.append(" and cId = ?");
		}
		if (Util.strIsNotEmpty(param.getMemo())) {
			sb.append(" and vMemo = ?");
		}
		if (param.getStartTime() != null) {
			sb.append(" and iAddTime >= ?");
		}
		if (param.getEndTime() != null) {
			sb.append(" and iAddTime <= ?");
		}
		if (param.getStatus() != null) {
			sb.append(" and tStatus = ?");
		}
		if (Util.strIsNotEmpty(param.getKey())) {
			sb.append(" and ( cId like ?");
			sb.append(" or vMemo like ? )");
		}
	}

	/**
	 * 消息各状态数据总数
	 * 
	 * @param param
	 * @return
	 */
	private String prepareCount(MessageQueryParam param) {
		StringBuilder sb = new StringBuilder();
		sb.append("select count(1) as num,tStatus ");
		sb.append(" from ").append(table);
		sb.append(" where 1=1 ");
		prepareCondition(sb, param);
		sb.append(" GROUP BY tStatus ");
		return sb.toString();
	}

	// public void reset(Connection conn) throws SQLException {
	// PreparedStatement ps = null;
	// try {
	// String sql = new StringBuilder("update ").append(table) //
	// .append(" set tStatus = ").append(Message.STATUS_NEW)//
	// .append(" where tStatus = ").append(Message.STATUS_QUEUED).toString();
	// log.debug(sql);
	// ps = conn.prepareStatement(sql);
	// ps.executeUpdate();
	// } finally {
	// JdbcUtil.close(ps);
	// }
	// }

	public long update(Connection conn, String id, short status, int tried, String memo) throws SQLException {
		long lastTime = new Date().getTime();
		PreparedStatement ps = null;
		try {
			ps = conn.prepareStatement(updateSql);
			ps.setShort(1, status);
			ps.setString(2, memo);
			ps.setLong(3, lastTime);
			ps.setInt(4, tried);
			ps.setString(5, id);
			ps.executeUpdate();
		} finally {
			JdbcUtil.close(ps);
		}
		return lastTime;
	}

	public MessageEntity get(Connection conn, String id) throws SQLException, ClassNotFoundException, IOException {
		PreparedStatement ps = null;
		try {
			ps = conn.prepareStatement(getSql);
			ps.setString(1, id);
			ResultSet rs = null;
			try {
				rs = ps.executeQuery();
				if (rs.next()) {
					Message m = this.readMessage(rs, 4);
					MessageEntity me = new MessageEntity(m);
					me.setAddTime(rs.getLong(1));
					me.setStatus(rs.getShort(2));
					return me;
				}
			} finally {
				JdbcUtil.close(rs);
			}
		} finally {
			JdbcUtil.close(ps);
		}
		return null;
	}

	protected Message readMessage(ResultSet rs, int index) throws SQLException, ClassNotFoundException, IOException {
		switch (type) {
		case TYPE_JSON:
			String js = rs.getString(index); // vJson
			return JsonUtil.parseObject(js, Message.class);
		// return JsonUtil.fromJson(js, Message.class);
		case TYPE_BLOB:
			InputStream is = rs.getBinaryStream(index); // bBlob
			return serializer.deserialize(is, Message.class);
		default:
			throw new IllegalStateException(String.format("Unknown message storage type %d", type));
		}
	}
	
	protected void prepareReloadSql(){
		StringBuilder sb = new StringBuilder();
		sb.append("select cId, iAddTime, iLastTime, tStatus, tTried, vMemo,");
		sb.append(this.getLob()).append(" from ").append(table);
		// 添加时间不得早于begin（排除过期消息），不得晚于end（排除新接收的消息）
		sb.append(" where (iAddTime > ? and iLastTime < ?");
		// 查询于服务器启动前创建的状态为（0:NEW/1:QUUED/2:SENDING），或服务器启动后创建的失败的消息
		sb.append(" and tStatus = ?");
		// 此消息必须是当前节点写入的，避免读取别的实例负责的数据
		sb.append(" and vNode = ?");
		// 按时间先后，先进先出，并限制每次查询的条数
		sb.append(") or (iAddTime <= ?");
		// 20230724,起点时间之前的未处理消息说明容器ip可能发生变化，查询条件需筛除ip
		sb.append(" and  tStatus = ?");
		sb.append(") order by iAddTime desc limit ?");
		reloadSql = sb.toString();
		log.info("Reload message SQL: {}", reloadSql);
	}

	public List<MessageEntity> reload(MessageRoller roller, Connection conn, //
			Date begin, Date end, short status, int limit) throws SQLException {
		List<MessageEntity> lt = new LinkedList<MessageEntity>();
		PreparedStatement us = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			// 修改单条记录状态用的SQL
			us = conn.prepareStatement(updateSql+" and tStatus = ?");
			// 查询在指定时间点前添加的、且未过期和未发送的消息
			ps = conn.prepareStatement(reloadSql);
			ps.setLong(1, begin.getTime());
			ps.setLong(2, end.getTime());
			ps.setShort(3, status);
			ps.setString(4, MessageConfig.getAddr());
			ps.setLong(5, begin.getTime());
			ps.setShort(6, status);
			ps.setInt(7, limit);
			// 执行查询，遍历返回的消息记录
			// long l = System.currentTimeMillis();
			rs = ps.executeQuery();
			// log.debug("Query completed in {}ms from {}", l1, table);
			// l = System.currentTimeMillis();
			long now = new Date().getTime();
			while (rs.next()) {
				String id = rs.getString(1);
				long addTime = rs.getLong(2);
				long lastTime = rs.getLong(3);
				// status = rs.getShort(4);
				int tried = rs.getInt(5);
				String memo = rs.getString(6);
				//
				us.setLong(3, now);
				us.setInt(4, tried);
				us.setString(5, id);
				us.setShort(6, status);
				//
				Message m = null;
				try {
					m = this.readMessage(rs, 7);
				} catch (Exception e) {
					log.error("Error on read message {}", id, e);
					us.setShort(1, Message.STATUS_FAILED);
					us.setString(2, e.getMessage());
					us.addBatch();
					continue;
				}
				if (m == null) {
					log.error("Message {} is null", id);
					us.setShort(1, Message.STATUS_FAILED);
					us.setString(2, "Message is null");
					us.addBatch();
					continue;
				}
				us.setShort(1, Message.STATUS_QUEUED);
				us.setString(2, "Message is reloaded");
				us.addBatch();
				// 不再持久化
				MessageEntity me = new MessageEntity(m, roller);
				me.setAddTime(addTime);
				me.setLastTime(lastTime);
				me.setStatus(status);
				me.setTried(tried);
				me.setMemo(memo);
				lt.add(me);
			}
			us.executeBatch();
			// int[] r = us.executeBatch();
			// log.info("Updated messages status {}", JsonUtil.toJSONString(r));
			us.clearBatch();
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(ps);
			JdbcUtil.close(us);
		}
		return lt;
	}

	/**
	 * 将QUEUED状态的消息重置为NEW，当消息被重新装载时，再置回QUEUED，以为标识
	 * 
	 * @param conn
	 * @throws SQLException
	 */
	public void reset(Connection conn) throws SQLException {
		PreparedStatement ps = null;
		try {
			String sql = new StringBuilder("update ").append(table) //
					.append(" set tStatus = ").append(Message.STATUS_NEW)//
					.append(" where tStatus = ").append(Message.STATUS_QUEUED).toString();
			log.debug(sql);
			ps = conn.prepareStatement(sql);
			ps.executeUpdate();
		} finally {
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 统计失效消息数量
	 * 
	 * @param conn
	 * @param beforeTime
	 * @param currentTime
	 * @param statuses
	 * @return
	 * @throws SQLException
	 */
	public int expiredNum(Connection conn, Date beforeTime, short... statuses) throws SQLException {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = conn.prepareStatement(prepareExpiredNum(statuses));
			ps.setLong(1, beforeTime.getTime());
			for (int i = 0; i < statuses.length; i++) {
				ps.setShort(i + 2, statuses[i]);
			}
			rs = ps.executeQuery();
			if (rs.next()) {
				return rs.getInt("num");
			}
			return 0;
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 统计备份表数据数量
	 * 
	 * @param conn
	 * @param backup
	 *            备份表名
	 * @return
	 * @throws SQLException
	 */
	public int backupDataNum(Connection conn, String backup) throws SQLException {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = conn.prepareStatement(prepareBackupNum(backup));
			rs = ps.executeQuery();
			if (rs.next()) {
				return rs.getInt("num");
			}
			return 0;
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 迁移过期数据到备份表
	 * 
	 * @param conn
	 * @param backup
	 *            备份表名
	 * @param beforeTime
	 *            N小时前时间
	 * @param statuses
	 *            数据状态集
	 * @return
	 * @throws SQLException
	 */
	public int moveExpiredData(Connection conn, String backup, int pageSize, long beforeTime, short... statuses)
			throws SQLException {
		PreparedStatement ps = null;
		try {
			ps = conn.prepareStatement(prepareMoveData(backup, pageSize, statuses));
			ps.setLong(1, beforeTime);
			for (int i = 0; i < statuses.length; i++) {
				ps.setShort(i + 2, statuses[i]);
			}
			return ps.executeUpdate();
		} finally {
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 批次删除过期数据
	 * 
	 * @param conn
	 * @param beforeTime
	 * @return
	 * @throws SQLException
	 */
	public int deleteData(Connection conn, long beforeTime, MsgDetailTM detailTm, String tableName, short... statuses)
			throws SQLException {
		PreparedStatement ps = null;
		try {
			// 开启事务
			conn.setAutoCommit(false);
			ps = conn.prepareStatement(prepareDelExpiredData(tableName));
			// ps.setLong(1, beforeTime);
			int num = ps.executeUpdate();
			detailTm.deleteData(conn, beforeTime, statuses);
			// 事务提交
			conn.commit();
			return num;
		} catch (Exception e) {
			// .在catch块内添加回滚事务，表示操作出现异常，撤销事务：
			conn.rollback();
		} finally {
			conn.setAutoCommit(true);
			JdbcUtil.close(ps);
		}
		return 0;
	}

	/**
	 * 删除过期数据
	 * 
	 * @param conn
	 * @param beforeTime
	 * @return
	 * @throws SQLException
	 */
	public int deleteData(Connection conn, long beforeTime, MsgDetailTM detailTm, short... statuses) throws SQLException {
		PreparedStatement ps = null;
		try {
			// 开启事务
			conn.setAutoCommit(false);
			ps = conn.prepareStatement(prepareDelExpiredData(statuses));
			ps.setLong(1, beforeTime);
			for (int i = 0; i < statuses.length; i++) {
				ps.setShort(i + 2, statuses[i]);
			}
			int num = ps.executeUpdate();
			detailTm.deleteData(conn, beforeTime, statuses);
			// 事务提交
			conn.commit();
			return num;
		} catch (Exception e) {
			// .在catch块内添加回滚事务，表示操作出现异常，撤销事务：
			conn.rollback();
		} finally {
			conn.setAutoCommit(true);
			JdbcUtil.close(ps);
		}
		return 0;
	}

	/**
	 * 删除已备份数据
	 * 
	 * @param conn
	 * @param beforeTime
	 * @return
	 * @throws SQLException
	 */
	public int delete(Connection conn, String backup, long beforeTime) throws SQLException {
		PreparedStatement ps = null;
		try {
			String sql = prepareDelete(backup);
			ps = conn.prepareStatement(sql);
			// ps.setLong(1, beforeTime);
			return ps.executeUpdate();
		} finally {
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 统计备份表的数量
	 * 
	 * @param conn
	 * @return
	 * @throws SQLException
	 */
	public int countBackupTabNum(Connection conn) throws SQLException {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			String tab = new StringBuilder(table).append("_%").toString();
			rs = conn.getMetaData().getTables(null, schema, tab, new String[] { "TABLE" });
			rs.last();
			return rs.getRow();
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 删除最老的备份表
	 * 
	 * @param conn
	 * @return
	 * @throws SQLException
	 */
	public void deleteOldestBackupTab(Connection conn) throws SQLException {
		String tabName = getBackupTabName(conn, false);
		log.debug("delete oldest backup table:{}", tabName);
		if (Util.strIsNotEmpty(tabName)) {
			this.drop(conn, tabName);
		}
	}

	/**
	 * 检查备份表是否存在，存在则返回表名，不存在则返回null
	 * 
	 * @param conn
	 * @return
	 * @throws SQLException
	 */
	public String backupExists(Connection conn) throws SQLException {
		String tabName = getBackupTabName(conn, true);
		log.debug("check backup is exist table:{} !", tabName);
		return tabName;
	}

	/**
	 * 查询备份表
	 * 
	 * @param conn
	 * @param flag
	 *            true查询最新的备份表，false查询最老的备份表
	 * @return
	 * @throws SQLException
	 * @throws ParseException
	 */
	private String getBackupTabName(Connection conn, boolean flag) throws SQLException {
		ResultSet rs = null;
		try {
			String tab = new StringBuilder(table).append("_%").toString();
			rs = conn.getMetaData().getTables(null, schema, tab, new String[] { "TABLE" });
			List<String> tableDate = new ArrayList<>();
			List<String> tableList = new ArrayList<>();
			while (rs.next()) {
				String tableName = rs.getString("TABLE_NAME");
				String[] str = tableName.split("_");
				tableList.add(tableName);
				tableDate.add(str[str.length - 1]);
			}
			if (tableList.isEmpty()) {
				return null;
			}
			int index = 0;
			String tempDate = tableDate.get(0);
			Date firstDate = Util.str2date(tempDate, "yyyyMMddHHmm");
			Date max = firstDate;
			Date min = firstDate;
			if (flag) {
				for (int i = 0; i < tableDate.size(); i++) {
					Date time = Util.str2date(tableDate.get(i), "yyyyMMddHHmm");
					if (time.getTime() > max.getTime()) {
						max = time;
						index = i;
					}
				}
			} else {
				for (int i = 0; i < tableDate.size(); i++) {
					Date time = Util.str2date(tableDate.get(i), "yyyyMMddHHmm");
					if (time.getTime() < min.getTime()) {
						min = time;
						index = i;
					}
				}
			}
			return tableList.get(index);
		} finally {
			JdbcUtil.close(rs);
		}

	}

	/**
	 * 得到备份表名
	 * 
	 * @param currentTimeStr
	 * @return
	 */
	public String getBackupTabName(String currentTimeStr) {
		return new StringBuilder(table).append("_").append(currentTimeStr).toString();
	}

	/**
	 * 给页面提供分页查询
	 * 
	 * @param conn
	 * @return
	 * @throws SQLException
	 * @throws IOException
	 * @throws ClassNotFoundException
	 */
	public List<MessageEntity> list(Connection conn, MessageQueryParam pm)
			throws SQLException, ClassNotFoundException, IOException {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = conn.prepareStatement(prepareList(pm));
			int i = setCondition(ps, pm);
			ps.setInt(i++, (pm.getPageNo() - 1) * pm.getPageSize());
			ps.setInt(i, pm.getPageSize());
			rs = ps.executeQuery();
			List<MessageEntity> lt = new ArrayList<>();
			while (rs.next()) {
				MessageEntity me = new MessageEntity();
				me.setAddTime(rs.getLong("iAddTime"));
				me.setLastTime(rs.getLong("iLastTime"));
				me.setMemo(rs.getString("vMemo"));
				//
				if (pm.isLob()) {
					int c = rs.findColumn(this.getLob());
					me.setMessage(this.readMessage(rs, c));
				} else {
					Message m = new Message();
					m.setId(rs.getString("cId"));
					m.setStatus(rs.getShort("tStatus"));
					m.setContent(null);
					me.setMessage(m);
				}
				lt.add(me);
			}
			return lt;
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 各消息状态总数
	 * 
	 * @param conn
	 * @param param
	 * @return
	 * @throws SQLException
	 */
	public List<Map<String, Object>> count(Connection conn, MessageQueryParam param) throws SQLException {
		PreparedStatement ps = null;
		ResultSet rs = null;
		try {
			ps = conn.prepareStatement(prepareCount(param));
			setCondition(ps, param);
			rs = ps.executeQuery();
			List<Map<String, Object>> list = new ArrayList<>();
			while (rs.next()) {
				Map<String, Object> map = new HashMap<>();
				map.put("count", rs.getInt("num"));
				map.put("tStatus", rs.getShort("tStatus"));
				list.add(map);
			}
			return list;
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(ps);
		}
	}

	/**
	 * 分页查询设置参数
	 * 
	 * @param ps
	 * @param param
	 * @return
	 * @throws SQLException
	 */
	private int setCondition(PreparedStatement ps, MessageQueryParam param) throws SQLException {
		int index = 1;
		if (Util.strIsNotEmpty(param.getId())) {
			ps.setString(index++, param.getId());
		}
		if (Util.strIsNotEmpty(param.getMemo())) {
			ps.setString(index++, param.getMemo());
		}
		if (param.getStartTime() != null) {
			ps.setLong(index++, param.getStartTime().getTime());
		}
		if (param.getEndTime() != null) {
			ps.setLong(index++, param.getEndTime().getTime());
		}
		if (param.getStatus() != null) {
			ps.setLong(index++, param.getStatus());
		}
		if (Util.strIsNotEmpty(param.getKey())) {
			String key = new StringBuilder("%").append(param.getKey()).append("%").toString();
			ps.setString(index++, key);
			ps.setString(index++, key);
		}
		return index;
	}

	// -----------

	public short getType() {
		return type;
	}

	public void setType(short type) {
		this.type = type;
	}

	public ObjectSerializer getSerializer() {
		return serializer;
	}

	public void setSerializer(ObjectSerializer serializer) {
		this.serializer = serializer;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public static short getTypeJson() {
		return TYPE_JSON;
	}
}
